package com.haust.item.com.sxt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.haust.commons.exception.DaoException;
import com.haust.commons.pojo.HaustResult;
import com.haust.dao.RedisDao;
import com.haust.item.com.sxt.feign.FrontSearchFeign;
import com.haust.item.com.sxt.mapper.ItemMapper4Search;
import com.haust.item.com.sxt.service.ItemService;
import com.haust.mapper.TbItemCatMapper;
import com.haust.mapper.TbItemDescMapper;
import com.haust.mapper.TbItemMapper;
import com.haust.mapper.TbItemParamItemMapper;
import com.haust.pojo.TbItem;
import com.haust.pojo.TbItemCat;
import com.haust.pojo.TbItemDesc;
import com.haust.pojo.TbItemParamItem;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ItemServiceImpl implements ItemService {
    @Autowired
    private TbItemMapper itemMapper;

    @Autowired
    private TbItemParamItemMapper tbItemParamItemMapper;

    @Autowired
    private TbItemDescMapper tbItemDescMapper;

    @Autowired
    private TbItemCatMapper tbItemCatMapper;

    @Autowired
    private ItemMapper4Search itemMapper4Search;

    @Autowired
    private RedisDao redisDao;

    @Autowired
    private FrontSearchFeign frontSearchFeign;


    @Value("${Haust.incr.item}")
    private String itemIncrKey;

    @Value("${Haust.incr.itemDesc}")
    private String itemDescIncrKey;

    @Value("${Haust.incr.itemParamItem}")
    private String itemParamItemIncrKey;

    @Value("${Haust.frontend.details.item}")
    private String itemKeyPrefix;

    @Value("${Haust.frontend.details.itemDesc}")
    private String itemDescKeyPrefix;

    @Value("${Haust.frontend.details.itemParamItem}")
    private String itemParamItemKeyPrefix;


    @Override
    @LcnTransaction
    @Transactional(rollbackFor = {DaoException.class})
    public HaustResult updateItemNum4CreateOrder(List<Map<String, Object>> params) {


        for (Map<String, Object> map : params) {
            //获取商品主键
            Long itemId = Long.parseLong(map.get("itemId").toString());
            //获取商品数量
            Integer num = Integer.parseInt(map.get("num").toString());
            //获取更新时间
            Date updated = new Date(Long.parseLong(map.get("updated").toString()));

            //获取该商品
            TbItem tbItem = itemMapper.selectById(itemId);
            tbItem.setNum(tbItem.getNum()-num);
            tbItem.setUpdated(updated);

            //更新库存
            try {
                itemMapper.updateById(tbItem);
            }catch (Exception e){
                e.printStackTrace();
                throw new DaoException("服务忙，请稍后");
            }
        }

        return HaustResult.ok();
    }

    @Override
    public HaustResult selectTbItemAllByPage(Integer page, Integer rows) {
        IPage<TbItem> itemIPage = new Page<>(page, rows);
        IPage<TbItem> resultPages = itemMapper.selectPage(itemIPage, null);

        List<TbItem> records = resultPages.getRecords();
        long total = resultPages.getTotal();

        HashMap<String, Object> map = new HashMap<>();
        map.put("result", records);
        map.put("total", total);

        return HaustResult.ok(map);
    }


    /**
     * 保证 三张表的添加 同时成功，或者同时失败
     *
     * @param tbItem          商品基本信息
     * @param tbItemDesc      详情图文介绍
     * @param tbItemParamItem 规格与包装
     * @return
     */
    @Override
    @Transactional(rollbackFor = {DaoException.class})
    public HaustResult insertTbItem(TbItem tbItem, TbItemDesc tbItemDesc, TbItemParamItem tbItemParamItem) {

        //数据完整性处理
        //生成唯一主键
        Long itemId = null;
        Long itemDescId = null;
        Long itemParamItem = null;
        try {
            itemId = redisDao.incr(itemIncrKey);
            itemDescId = redisDao.incr(itemDescIncrKey);
            itemParamItem = redisDao.incr(itemParamItemIncrKey);
        } catch (RuntimeException e) {
            e.printStackTrace();
            return HaustResult.error("服务繁忙，请稍后再试！");
        }
        Date date = new Date();

        //商品数据
        tbItem.setId(itemId);
        tbItem.setStatus(1); //新添加的商品状态为正常
        tbItem.setCreated(date);
        tbItem.setUpdated(date);

        //商品详情
        tbItemDesc.setItemId(itemDescId);
        tbItemDesc.setCreated(date);
        tbItemDesc.setUpdated(date);

        //规格
        tbItemParamItem.setItemId(itemId);
        tbItemParamItem.setId(itemParamItem);
        tbItemParamItem.setCreated(date);
        tbItemParamItem.setUpdated(date);


        try {
            itemMapper.insert(tbItem);
            tbItemDescMapper.insert(tbItemDesc);
            tbItemParamItemMapper.insert(tbItemParamItem);

            //新增成功，将数据添加进入ES中
            frontSearchFeign.add(
                    selectItem4SearchById(itemId)
            );

        } catch (Exception e) {
            e.printStackTrace();
            throw new DaoException("服务繁忙，稍后再试");
        }

        return HaustResult.ok();
    }


    /**
     * 根据 Id 将 状态设置为  3 表示删除
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = {DaoException.class})
    public HaustResult deleteItemById(Long id) {
        TbItem tbItem = itemMapper.selectById(id);

        //存储查询到的 上一次修改的时间 作为，修改的条件，不满足说明，其他线程给我修改了，然会错误
        QueryWrapper<TbItem> updateCondition = new QueryWrapper<>();
        updateCondition.
                eq("updated", tbItem.getUpdated())
                .eq("id", id);

        tbItem.setUpdated(new Date());
        tbItem.setStatus(3); //将商品的状态设置为3 表示已删除

        try {
            itemMapper.update(tbItem, updateCondition);

            //将数据从ES中删除
            frontSearchFeign.removeById(id);

            //修改为删除状态成功，将数据从redis中移除
            redisDao.del(itemKeyPrefix + id);
            redisDao.del(itemDescKeyPrefix + id);
            redisDao.del(itemParamItemKeyPrefix + id);

        } catch (RuntimeException e) {
            e.printStackTrace();
            throw new DaoException(e.getMessage());
        }
        return HaustResult.ok();
    }

    @Override
    @Transactional(rollbackFor = {DaoException.class})
    public HaustResult onshelfItemById(Long id) {
        TbItem tbItem = itemMapper.selectById(id);

        //存储查询到的 上一次修改的时间 作为，修改的条件，不满足说明，其他线程给我修改了，然会错误
        QueryWrapper<TbItem> updateCondition = new QueryWrapper<>();
        updateCondition.
                eq("updated", tbItem.getUpdated())
                .eq("id", id);


        tbItem.setUpdated(new Date());
        tbItem.setStatus(1); //将商品的状态设置为1 表示上架

        try {
            itemMapper.update(tbItem, updateCondition);

            //上架成功成功，将数据添加进入ES中
            frontSearchFeign.add(
                    selectItem4SearchById(id)
            );
        } catch (RuntimeException e) {
            e.printStackTrace();
            throw new DaoException(e.getMessage());
        }
        return HaustResult.ok();
    }


    @Override
    @Transactional(rollbackFor = {DaoException.class})
    public HaustResult offshelfItemById(Long id) {
        TbItem tbItem = itemMapper.selectById(id);
        //存储查询到的 上一次修改的时间 作为，修改的条件，不满足说明，其他线程给我修改了，然会错误
        QueryWrapper<TbItem> updateCondition = new QueryWrapper<>();
        updateCondition.
                eq("updated", tbItem.getUpdated())
                .eq("id", id);

        tbItem.setUpdated(new Date());
        tbItem.setStatus(2); //将商品的状态设置为2 表示下架

        try {
            itemMapper.update(tbItem, updateCondition);

            //将数据从ES中删除
            frontSearchFeign.removeById(id);

            //下架状态，将数据从redis中移除
            redisDao.del(itemKeyPrefix + id);
            redisDao.del(itemDescKeyPrefix + id);
            redisDao.del(itemParamItemKeyPrefix + id);
        } catch (RuntimeException e) {
            e.printStackTrace();
            throw new DaoException(e.getMessage());
        }
        return HaustResult.ok();
    }

    @Override
    public HaustResult preUpdateItem(Long id) {
        //查询商品
        TbItem tbItem = itemMapper.selectById(id);


        //查询 商品类别
        TbItemCat tbItemCat = tbItemCatMapper.selectById(tbItem.getCid());

        //查询商品详情
        TbItemDesc tbItemDesc = tbItemDescMapper.selectById(id);

        //查询商品的 参数具体信息
        QueryWrapper<TbItemParamItem> tbItemParamItemQueryWrapper = new QueryWrapper<>();
        tbItemParamItemQueryWrapper.eq("item_id", id);
        TbItemParamItem tbItemParamItem = tbItemParamItemMapper.selectOne(tbItemParamItemQueryWrapper);

        HashMap<String, Object> map = new HashMap<>();
        map.put("itemCat", tbItemCat);
        map.put("item", tbItem);
        map.put("itemDesc", tbItemDesc);
        map.put("itemParamItem", tbItemParamItem);


        return HaustResult.ok(map);
    }

    @Override
    @Transactional(rollbackFor = {DaoException.class})
    public HaustResult updateTbItem(TbItem tbItem, TbItemDesc tbItemDesc, String paramData) {

        //更新tb_item ，进行CAS保障更新的同步安全
        //根据Id 查询到之前的 更新时间

        TbItem oldItem = itemMapper.selectById(tbItem.getId());
        TbItemDesc oldTbItemDesc = tbItemDescMapper.selectById(tbItem.getId());
        QueryWrapper<TbItemParamItem> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("item_id", tbItem.getId());
        TbItemParamItem oldTbItemParamItem = tbItemParamItemMapper.selectOne(queryWrapper);


        Date date = new Date();

        /*
        更新tb_item表
         */
        tbItem.setUpdated(date);
        QueryWrapper<TbItem> tbItemQueryWrapper = new QueryWrapper<>();
        //根据 查询到的之前的 Item 的更新时间，作为 乐观锁的期望值 去更新内容
        tbItemQueryWrapper.eq("updated", oldItem.getUpdated());


        /*
        更新tb_item_desc表
         */
        tbItemDesc.setUpdated(date);
        QueryWrapper<TbItemDesc> tbItemDescQueryWrapper = new QueryWrapper<>();
        tbItemDescQueryWrapper.eq("updated", oldTbItemDesc.getUpdated());



        /*
        更新 tb_item_param_item表
         */
        oldTbItemParamItem.setUpdated(date);
        oldTbItemParamItem.setParamData(paramData);
        QueryWrapper<TbItemParamItem> tbItemParamItemQueryWrapper = new QueryWrapper<>();
        tbItemParamItemQueryWrapper.eq("updated", oldTbItemParamItem.getUpdated());

        try {
            itemMapper.update(tbItem, tbItemQueryWrapper);
            tbItemDescMapper.update(tbItemDesc, tbItemDescQueryWrapper);
            tbItemParamItemMapper.update(oldTbItemParamItem, tbItemParamItemQueryWrapper);


            //更新成功，将数据添加进入ES中
            frontSearchFeign.add(
                    selectItem4SearchById(tbItem.getId())
            );

            //修改为删除状态成功，将数据从redis中移除
            redisDao.del(itemKeyPrefix + tbItem.getId());
            redisDao.del(itemDescKeyPrefix + tbItem.getId());
            redisDao.del(itemParamItemKeyPrefix + tbItem.getId());
        } catch (RuntimeException e) {
            e.printStackTrace();
            throw new DaoException("服务忙，请稍后！");
        }

        return HaustResult.ok();
    }

    @Override
    public HaustResult selectItem4Search() {
        List<Map<String, Object>> maps = itemMapper4Search.selectItem4Search();
        return HaustResult.ok(maps);
    }

    /**
     * 根据主键 查找 数据库中 该记录
     *
     * @param itemId
     * @return
     */
    private Map<String, Object> selectItem4SearchById(Long itemId) {
        return itemMapper4Search.selectItem4SearchById(itemId);
    }
}

